package gu.simplemq.jms;

import java.util.Map;
import java.util.Properties;
import javax.jms.Connection;
import javax.jms.JMSException;

import org.apache.activemq.jms.pool.PooledConnectionFactory;

import gu.simplemq.IMQContext;
import gu.simplemq.pool.BaseMQPool;
import gu.simplemq.utils.IntrospectionSupport;
/**
 * 延迟初始化的 {@link Connection} 资源池（线程安全）<br>
 * @author guyadong
 *
 */
public abstract class JmsPoolLazy extends BaseMQPool<Connection> implements JmsConstants{
	private volatile PooledConnectionFactory pool;
	private String username;
	private String password;
	@SuppressWarnings("rawtypes")
	public JmsPoolLazy (Map props, IMQContext runtimeContext) {
		super(runtimeContext.getPropertiesHelper().initParameters(props), runtimeContext.getPropertiesHelper().getLocationlURI(props));
		// set field value for username,password
		// 这里不能用归一化的parameters变量，而要用原始输入的props用于初始化 username,password字段
		// 因为initParameters方法会修改props中的字段
		IntrospectionSupport.setProperties(this, props, false);
	}
	@SuppressWarnings("rawtypes")
	public JmsPoolLazy (Properties props, IMQContext runtimeContext) {
		this((Map)props, runtimeContext);
	}
	public abstract PooledConnectionFactory createPooledConnectionFactory(Properties properties);
	public void setUsername(String username) {
		this.username = username;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	private PooledConnectionFactory createPool(){
		PooledConnectionFactory pool = createPooledConnectionFactory(properties);
		logger.info("jms pool initialized(连接池初始化)  {} ",getCanonicalURI());
		return pool;
	}

	@Override
	public Connection borrow(){
		// double-checked locking
		if(null == pool){
			synchronized (this){
				if(null == pool){
					pool = createPool();
				}
			}
		}
        try {
			return pool.createConnection(username,password);
		} catch (JMSException e) {
			throw new MQPoolException(e);
		}
    }
    
	@Override
    public void release(Connection r) {
        if (r != null){
            try {
				r.close();
			} catch (JMSException e) {
				throw new RuntimeException(e);
			}
        }
    }
	@Override
	public void close(){
		// double check
		if(pool != null){
			synchronized (this){
				if(pool != null){
					logger.info("discard jms pool: {}",this);
					try {
						pool.stop();
						pool = null;
						closed = true;
					} catch (Exception e) {
						throw new MQPoolException(e);
					}
				}
			}
		}
	}
}
